package sg.edu.nus.iss.jass.gui;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionListener;
import java.io.FileInputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import javax.swing.DefaultCellEditor;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;

import sg.edu.nus.iss.jass.model.CompanyDTO;
import sg.edu.nus.iss.jass.model.JobAdvertDTO;
import sg.edu.nus.iss.jass.model.SkillDTO;

/**
 * @version 1.0
 * @author SE19 Team 1
 * 
 */
public class AddJobAdvertPanel extends JPanel {
	private static final long serialVersionUID = 1L;

	public static final String BTN_ADD_JOBADVERT = "btnAddJobAdvert";
	public static final String BTN_CLEAR = "btnClear";
	
	private List<SkillDTO> skills;
	private List<CompanyDTO> companies;
	
	private int numRows = 0;
	private Properties properties;
	private JTextField txtJobTitle, txtYrExp, txtMinSalary, txtMaxSalary, txtStartDt, txtLoc;
	private JButton btnAddJobAdvert, btnClear;
	private JComboBox cbCompanies;
	private JTextArea txtJobDesc;
	private String currUser;
	private DateFormat df = new SimpleDateFormat("dd/MM/yyyy");
	
	private DefaultTableModel defaultTableModel = new DefaultTableModel() {
		private static final long serialVersionUID = 1L;
		
		public boolean isCellEditable(int row, int column) {
			boolean isEditable = false;
			if(column == 0 || column == 3)
				isEditable = true;
			
			return isEditable;
		}
		
		public Class<?> getColumnClass(int columnIndex) {
			if (columnIndex == 0)
				return Boolean.class;
			else
				return super.getColumnClass(columnIndex);
		}
	};
	private JTable skillTable = new JTable(defaultTableModel);
	
	// Class Constructor.
	public AddJobAdvertPanel(String currUser, List<SkillDTO> skills, List<CompanyDTO> companies) {
		this.setOpaque(false);
		this.setLayout(new BorderLayout());
		
		this.currUser = currUser;
		this.skills = skills;
		this.companies = companies;
		
		loadConfiguration();
		add(constructJobAdvertPanel(), BorderLayout.CENTER);
	}
	
	public void addComponentActionListener(ActionListener listener) {
		btnAddJobAdvert.addActionListener(listener);
		btnClear.addActionListener(listener);
	}
	
	public JobAdvertDTO getFormData() {
		JobAdvertDTO jobAdvertDTO = new JobAdvertDTO();
		String errorMsg = validateAndCreateJobAdvertDTO(jobAdvertDTO);
		
		if(!errorMsg.isEmpty()) {
			String displayMsg = properties.getProperty("error.jobAdvert.addUnsuccessful.main");
			displayMsg += errorMsg.toString();
			JOptionPane.showMessageDialog(this, displayMsg, properties.getProperty("mainMenu.label.addJobAdvert"), JOptionPane.INFORMATION_MESSAGE);
			return null;
		}
		return jobAdvertDTO;
	}
	
	public void clearFormData() {
		// Reset the components values.
		txtJobTitle.setText("");
		txtYrExp.setText("");
		txtMinSalary.setText("");
		txtMaxSalary.setText("");
		txtStartDt.setText("");
		txtLoc.setText("");
		txtJobDesc.setText("");
		cbCompanies.setSelectedIndex(0);
		
		// Reset the table values.
		for(int n = 0; n < defaultTableModel.getRowCount(); n++) {
			defaultTableModel.setValueAt(new Boolean(false), n, 0);
			defaultTableModel.setValueAt(properties.getProperty("option.proficiency.beginner"), n, 3);
		}
	}
	
	private void loadConfiguration() {
		try {
			properties = new Properties();
			FileInputStream in = new FileInputStream("properties/application.properties");
			properties.load(in);
			in.close();
		}
		catch(Exception ex) {
			ex.printStackTrace();
		}
	}
	
	private JPanel constructJobAdvertPanel() {
		// 1. To determine the title of the Job Advert.
		String jobAdvertTitle = properties.getProperty("title.jobadvert.addJobAdvert");
		
		// 2. Construct Customer Details Panel
		GridBagLayout jobAdvertGridLayout = new GridBagLayout();
		JPanel jobAdvertDetailPanel = new JPanel(jobAdvertGridLayout);
		jobAdvertDetailPanel.setOpaque(false);
		
		JLabel label;
		
		label = createLabel(properties.getProperty("label.jobadvert.RefCode"));
		addRow(jobAdvertDetailPanel, label, createDataLabel("-"));
		
		label = createLabel(properties.getProperty("label.jobadvert.title"));
		txtJobTitle = createTextField(40);
		addRow(jobAdvertDetailPanel, label, txtJobTitle);
		
		label = createLabel(properties.getProperty("label.jobadvert.desc"));
		txtJobDesc = createTextArea();
		addRow(jobAdvertDetailPanel, label, new JScrollPane(txtJobDesc));
		
		label = createLabel(properties.getProperty("label.jobadvert.yearOfExp"));
		txtYrExp = createTextField(40);
		addRow(jobAdvertDetailPanel, label, txtYrExp);
		
		label = createLabel(properties.getProperty("label.jobadvert.salaryRange"));
		addRow(jobAdvertDetailPanel, label, constructSalaryPanel());
		
		label = createLabel(properties.getProperty("label.jobadvert.startDate"));
		txtStartDt = createTextField(40);
		addRow(jobAdvertDetailPanel, label, txtStartDt);

		label = createLabel(properties.getProperty("label.jobadvert.location"));
		txtLoc = createTextField(40);
		addRow(jobAdvertDetailPanel, label, txtLoc);

		label = createLabel(properties.getProperty("label.jobadvert.skill"));
		skillTable = constructSkillTable();
		addRow(jobAdvertDetailPanel, label, new JScrollPane(skillTable));
		
		label = createLabel(properties.getProperty("label.jobadvert.company"));
		cbCompanies = constructCompanyMenu();
		addRow(jobAdvertDetailPanel, label, cbCompanies);

		label = createLabel(properties.getProperty("label.jobadvert.advertOwner"));
		addRow(jobAdvertDetailPanel, label, createDataLabel(currUser));
		
		JPanel buttonPanel = new JPanel();
		buttonPanel.setOpaque(false);
		buttonPanel.setLayout(new GridLayout(0, 2, 5, 0));
		
		btnAddJobAdvert = new JButton(properties.getProperty("button.label.addJobAdvert"));
		btnAddJobAdvert.setName(BTN_ADD_JOBADVERT);
		btnAddJobAdvert.setFont(new Font("Calibri", Font.BOLD, 16));
		btnClear = new JButton(properties.getProperty("button.label.clear"));
		btnClear.setName(BTN_CLEAR);
		btnClear.setFont(new Font("Calibri", Font.BOLD, 16));
		buttonPanel.add(btnAddJobAdvert);
		buttonPanel.add(btnClear);
		
		addRow(jobAdvertDetailPanel, null, buttonPanel);
		
		// 3. Construct Header Panel
		JPanel headerPanel = new JPanel();
		headerPanel.setOpaque(false);
		headerPanel.setLayout(new GridLayout(0, 1, 10, 10));
		
		JLabel msgLabel = new JLabel(jobAdvertTitle);
		msgLabel.setFont(new Font("Calibri", Font.PLAIN, 30));
		msgLabel.setHorizontalAlignment(SwingConstants.CENTER);
		headerPanel.add(msgLabel);
		
		ImageIcon imgDivider = new ImageIcon("./images/divider.jpg");
		JLabel lblDivider = new JLabel(imgDivider);
		headerPanel.add(lblDivider);
		
		JPanel jobAdvertPanel = new JPanel();
		jobAdvertPanel.setOpaque(false);
		jobAdvertPanel.setLayout(new BorderLayout());
		jobAdvertPanel.add(headerPanel, BorderLayout.NORTH);
		jobAdvertPanel.add(jobAdvertDetailPanel, BorderLayout.CENTER);
		
		return jobAdvertPanel;
	}

	private void addRow(JPanel panel, Component label, Component component) {
		GridBagConstraints constraints = new GridBagConstraints();
		constraints.insets = new Insets(5, 5, 5, 5);
		constraints.fill = GridBagConstraints.HORIZONTAL;
		
		if(label != null) {
			constraints.gridx = 0;
			constraints.gridy = numRows;
			panel.add(label, constraints);
		}
		
		if(component != null) {
			constraints.gridx = 1;
			constraints.gridy = numRows;
			panel.add(component, constraints);
		}
		numRows++;
	}
	
	private JLabel createLabel(String label) {
		JLabel jlabel = new JLabel(label);
		jlabel.setFont(new Font("Calibri", Font.BOLD, 16));
		jlabel.setHorizontalAlignment(JLabel.RIGHT);
		jlabel.setVerticalAlignment(JLabel.TOP);
		return jlabel;
	}
	
	private JLabel createDataLabel(String label) {
		JLabel jlabel = new JLabel(label);
		jlabel.setFont(new Font("Calibri", Font.PLAIN, 16));
		jlabel.setHorizontalAlignment(JLabel.LEFT);
		jlabel.setVerticalAlignment(JLabel.TOP);
		return jlabel;
	}
	
	private JTextField createTextField(int fieldSize) {
		JTextField textfield = new JTextField(fieldSize);
		textfield.setFont(new Font("Calibri", Font.PLAIN, 16));
		return textfield;
	}

	private JTextArea createTextArea() {
		JTextArea textarea = new JTextArea(5, 40);
		textarea.setFont(new Font("Calibri", Font.PLAIN, 16));
		return textarea;
	}
	
	private JPanel constructSalaryPanel() {
		JPanel salaryPanel = new JPanel();
		
		JLabel lblFrom = createLabel("From $");
		JLabel lblTo = createLabel(" To $");
		txtMinSalary = createTextField(20);
		txtMaxSalary = createTextField(20);
		salaryPanel.add(lblFrom);
		salaryPanel.add(txtMinSalary);
		salaryPanel.add(lblTo);
		salaryPanel.add(txtMaxSalary);
		
		return salaryPanel;
	}
	
	private JTable constructSkillTable() {
		String[] columnNames = new String[4];
		columnNames[0] = "";
		columnNames[1] = properties.getProperty("table.column.skillDesc");
		columnNames[2] = properties.getProperty("table.column.type");
		columnNames[3] = properties.getProperty("table.column.proficiency");
		
		Object[][] data = new Object[skills.size()][4];
		for(int n = 0; n < skills.size(); n++) {
			SkillDTO skillDTO = skills.get(n);
			
			data[n][0] = new Boolean(false);
			data[n][1] = skillDTO.getDescription();
			data[n][2] = skillDTO.getType();
			data[n][3] = properties.getProperty("option.proficiency.beginner");
		}
		
		defaultTableModel.setDataVector(data, columnNames);
		skillTable.setModel(defaultTableModel);
		
		//Set Table Columns widths Begin
		JCheckBox checkbox = new JCheckBox();
		TableColumn col = skillTable.getColumnModel().getColumn(0);
		col.setCellEditor(new DefaultCellEditor(checkbox));
	    col.setPreferredWidth(10);
	    
	    col = skillTable.getColumnModel().getColumn(1);
	    col.setPreferredWidth(200);
	    col = skillTable.getColumnModel().getColumn(2);
	    col.setPreferredWidth(80);
	    
	    col = skillTable.getColumnModel().getColumn(3);
	    JComboBox comboBox = new JComboBox();
	    comboBox.addItem(properties.getProperty("option.proficiency.beginner"));
	    comboBox.addItem(properties.getProperty("option.proficiency.intermediate"));
	    comboBox.addItem(properties.getProperty("option.proficiency.expert"));
	    col.setCellEditor(new DefaultCellEditor(comboBox));
	    
	  	//Set Table Columns widths Begin
	    skillTable.setPreferredScrollableViewportSize(new Dimension(470,80));
	    skillTable.setFont(new Font("Calibri", Font.PLAIN, 12));
	    skillTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
	    
	    return skillTable;
	}
	
	private JComboBox constructCompanyMenu() {
		String[] companiesMenu = new String[companies.size()];
		
		for(int n = 0; n < companies.size(); n++) {
			CompanyDTO companyDTO = companies.get(n);
			if(!companyDTO.getIsAnonymous().booleanValue())
				companiesMenu[n] = companyDTO.getName();
			else
				companiesMenu[n] = companyDTO.getAlternativeDesc();
		}
		
		cbCompanies = new JComboBox(companiesMenu);
		cbCompanies.setPreferredSize(new Dimension(480,20));
		return cbCompanies;
	}
	
	private String validateAndCreateJobAdvertDTO(JobAdvertDTO jobAdvertDTO) {
		String errorMsg = "";
		
		if(txtJobTitle.getText().trim().length() == 0)
			errorMsg += properties.getProperty("error.jobAdvert.jobTitleRequired");
		else
			jobAdvertDTO.setJobTitle(txtJobTitle.getText().trim());
		
		if(txtJobDesc.getText().trim().length() == 0)
			errorMsg += properties.getProperty("error.jobAdvert.jobDescRequired");
		else
			jobAdvertDTO.setJobDescription(txtJobDesc.getText().trim());
		
		if(txtLoc.getText().trim().length() == 0)
			errorMsg += properties.getProperty("error.jobAdvert.locationRequired");
		else 
			jobAdvertDTO.setLocation(txtLoc.getText().trim());
		
		if(txtYrExp.getText().trim().length() == 0) {
			errorMsg += properties.getProperty("error.jobAdvert.yrOfExpRequired");
		}
		else {
			try {
				jobAdvertDTO.setYearOfExperience(Integer.parseInt(txtYrExp.getText().trim()));
			}
			catch(NumberFormatException ex) {
				errorMsg += properties.getProperty("error.jobAdvert.yrOfExpNonNumeric");
			}
		}
		
		if(txtMinSalary.getText().trim().length() == 0 || txtMaxSalary.getText().trim().length() == 0) {
			errorMsg += properties.getProperty("error.jobAdvert.salaryRangeRequired");
		}
		else {
			try {
				int minSalary = Integer.parseInt(txtMinSalary.getText().trim());
				int maxSalary = Integer.parseInt(txtMaxSalary.getText().trim());
				
				if(minSalary > maxSalary) {
					errorMsg += properties.getProperty("error.jobAdvert.minSalaryGreaterThanMaxSalary");
				}
				else {
					jobAdvertDTO.setSalaryRange(minSalary + "," + maxSalary);
				}
			}
			catch(NumberFormatException ex) {
				errorMsg += properties.getProperty("error.jobAdvert.salaryRangeNonNumeric");
			}
		}
		
		if(txtStartDt.getText().trim().length() == 0) {
			errorMsg += properties.getProperty("error.jobAdvert.startDtRequired");
		}
		else {
			try {
				jobAdvertDTO.setStartDate(df.parse(txtStartDt.getText().trim()));
			}
			catch(Exception ex) {
				errorMsg += properties.getProperty("error.jobAdvert.startDtUnknownFormat");
			}
		}
		
		// Construct the list of selected skill(s).
		List<SkillDTO> selectedSkills = new ArrayList<SkillDTO>();
		for(int n = 0; n < defaultTableModel.getRowCount(); n++) {
			Boolean tempSelection = (Boolean)defaultTableModel.getValueAt(n, 0);
			if(tempSelection.booleanValue()) {
				SkillDTO selectedSkillDTO = skills.get(n);
				selectedSkillDTO.setProficiencyLevel((String)defaultTableModel.getValueAt(n, 3));
				selectedSkills.add(selectedSkillDTO);
			}
		}
		if(selectedSkills.size() == 0)
			errorMsg += properties.getProperty("error.jobAdvert.skillsRequired");
		else
			jobAdvertDTO.setSkills(selectedSkills);
		
		// Non-Validation fields.
		jobAdvertDTO.setCompanyId(companies.get(cbCompanies.getSelectedIndex()).getId());
		jobAdvertDTO.setCompany(companies.get(cbCompanies.getSelectedIndex()));
		jobAdvertDTO.setAdvertiser(this.currUser);
		jobAdvertDTO.setStatus(1); // 1 = Active. All newly created JobAdvert will be set to 1.
		
		return errorMsg;
	}
	
	public void displayAddSuccessMsg() {
		JOptionPane.showMessageDialog(this, "New Job Advertisement Added Succesfully.", "Add Job Advert", JOptionPane.INFORMATION_MESSAGE);
	}
}
